﻿using System;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;
using System.Reflection;
using System.Collections;
using InfoJetSoft.Service.Entity;

namespace InfoJetSoft.Service.Util
{

    public class ExtXdMathFunction : IExtensionFunctions
	{
		private Form form = null;

		public ExtXdMathFunction( Form frm ){
			this.form = frm;
        }

        //CID 0755 //2011.01.14 //Begin
        #region IExtensionFunction Members

        public string Prefix
        {
            get { return this.form.Manifest.NsResolver.GetPrefix(this.NamespaceURI); }
        }

        public string NamespaceURI
        {
            get { return JetConstant.URI_XDMATH; }
        }

        public IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] argTypes)
        {
            //CID 0830 //2011.03.09 //Begin
            if (name.Equals("Nz"))
            {
                return new XPathFunction(this.form, prefix, name, 1, 1, argTypes, XPathResultType.Number);
            }
            //CID 0837 //2011.03.22 //Begin
            else if (name.Equals("Avg"))
            {
                return new XPathFunction(this.form, prefix, name, 1, 1, argTypes, XPathResultType.Number);
            }
            else if (name.Equals("Min"))
            {
                return new XPathFunction(this.form, prefix, name, 1, 1, argTypes, XPathResultType.Number);
            }
            else if (name.Equals("Max"))
            {
                return new XPathFunction(this.form, prefix, name, 1, 1, argTypes, XPathResultType.Number);
            }
            else if (name.Equals("Eval"))
            {
                return new XPathFunction(this.form, prefix, name, 2, 2, argTypes, XPathResultType.NodeSet);
            }
            //CID 0837 //2011.03.22 //End
            else
            {
                throw new InfoJetException("Unimplemented Function.", prefix + ":" + name);
            }
            //CID 0830 //2011.03.09 //End
        }

        public object InvokeFunction(string prefix, string name, XsltContext xsltContext, object[] args, XPathNavigator docContext)
        {
            //CID 0830 //2011.03.09 //Begin
            if (name.Equals("Nz"))
            {
                return this.Nz(args[0]);
            }
            //CID 0837 //2011.03.22 //Begin
            else if (name.Equals("Avg"))
            {
                return this.Avg(args[0]);
            }
            else if (name.Equals("Min"))
            {
                return this.Min(args[0]);
            }
            else if (name.Equals("Max"))
            {
                return this.Max(args[0]);
            }
            else if (name.Equals("Eval"))
            {
                return this.Eval(args[0], args[1]);
            }
            //CID 0837 //2011.03.22 //End
            else
            {
                throw new InfoJetException("Unimplemented Function.", prefix + ":" + name);
            }
            //CID 0830 //2011.03.09 //End
        }

        #endregion
        //CID 0755 //2011.01.14 //End

		public object Eval( object param1, object param2 )
		{
			XPathNodeIterator nodeIterator = (XPathNodeIterator) param1;
			
			ArrayList itemArray = new ArrayList();
			
			while( nodeIterator.MoveNext() )
			{
				//CID 0837 //2011.03.22 //Begin
                string expr = (string)param2;
                XmlNode currentNode = ((System.Xml.IHasXmlNode)nodeIterator.Current).GetNode();
                string result = XPathEvaluator.evaluateStringValue(this.form, currentNode, expr);
				itemArray.Add( result );
                //CID 0837 //2011.03.22 //End
            }

			//创建一个新文档。
			XmlDocument evalDoc = new XmlDocument();
			XmlElement rootElement = evalDoc.CreateElement( "item" );
			evalDoc.AppendChild( rootElement );
			
			foreach( string item in itemArray )
			{
				XmlElement valueElement = evalDoc.CreateElement( "item" );
                //CID 0837 //2011.03.22 //Begin
                valueElement.InnerText =  item;
                //CID 0837 //2011.03.22 //End
                rootElement.AppendChild(valueElement);
			}
			return evalDoc.CreateNavigator().Select( "/item/item" );
		}

		public object Nz( object param )
		{
			XPathNodeIterator nodeIterator = (XPathNodeIterator) param;
            //CID 1029 //2011.11.22 //Begin
            bool needsNz = false;
            foreach (XPathNavigator nodeNav in nodeIterator)
            {
                if (nodeNav.Value.Length <= 0)
                {
                    needsNz = true;
                    break;
                }
            }
            if (needsNz)
            {
                XmlDocument evalDoc = new XmlDocument();
                XmlElement rootElement = evalDoc.CreateElement("item");
                evalDoc.AppendChild(rootElement);

                while (nodeIterator.MoveNext())
                {
                    XmlElement valueElement = evalDoc.CreateElement("item");
                    if (nodeIterator.Current.Value.Length <= 0)
                    {
                        valueElement.InnerText = "0";
                    }
                    else
                    {
                        valueElement.InnerText = nodeIterator.Current.Value;
                    }
                    rootElement.AppendChild(valueElement);
                }
                return rootElement.CreateNavigator().Select("item");
            }
            else
            {
                return param;
            }
            //CID 1029 //2011.11.22 //End
		}
	
		public object Min( object param ){
			double min = 0;
			bool inited = false;
			string nanValue = "";
			XPathNodeIterator nodeIterator = (XPathNodeIterator) param;
			while (nodeIterator.MoveNext()) {
				string nodeValue = nodeIterator.Current.Value.Trim();
				if( nodeValue.Length > 0 ){
					try{
						double doubleValue = System.Double.Parse( nodeValue );
						if( !inited ){
							min = doubleValue;
							inited = true;
						}else{
							if( min > doubleValue ){
								min = doubleValue;
							} 
						}
					}catch( Exception e ){
						nanValue = "NaN";
						break;
					}
				}
			}
			if( nanValue.Length > 0 ){
				return nanValue;
			}
			if( !inited ){
				return "";
			}else{
				return min;
			}
		}
	
		public object Max( object param ){
			double max = 0;
			bool inited = false;
			string nanValue = "";
			XPathNodeIterator nodeIterator = (XPathNodeIterator) param;
			while (nodeIterator.MoveNext()) {
				String nodeValue = nodeIterator.Current.Value.Trim();
				if( nodeValue.Length > 0 ){
					try{
						double doubleValue = System.Double.Parse( nodeValue );
						if( !inited ){
							max = doubleValue;
							inited = true;
						}else{
							if( max < doubleValue ){
								max = doubleValue;
							} 
						}
					}catch( Exception e ){
						nanValue = "NaN";
						break;
					}
				}
			}
			if( nanValue.Length > 0 ){
				return nanValue;
			}
			if( !inited ){
				return "";
			}else{
				return max;
			}
		}

		public object Avg( object param ){
			string nanValue = "";
			double sum = 0;
			int count = 0;
			XPathNodeIterator nodeIterator = (XPathNodeIterator) param;
			while (nodeIterator.MoveNext()) {
				string nodeValue = nodeIterator.Current.Value.Trim();
				if( nodeValue.Length > 0 ){
					try{
						double doubleValue = System.Double.Parse( nodeValue );
						sum += doubleValue;
						count ++;
					}catch( Exception e ){
						nanValue = "NaN";
						break;
					}
				}
			}
			if( nanValue.Length > 0 ){
				return nanValue;
			}else{
				if( sum == 0 && count == 0 ){
					return "";
				}else{
					return sum / count;
				}
			}
		}
    }
}